/*
 * This file is part of the Sx Framework Library.
 * 
 * Copyright (C) 2013 University of Colorado Denver
 * <min.choi@ucdenver.edu> <shane.transue@ucdenver.edu>
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy 
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
 * copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in 
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 */
#include <sxVega_TetgenMassSpringMeshStorage.h>

/* Simulation Object Created by this Storage Type */
#include <sxMassSpringMesh.h>

/* Tetgen Tetrahedra File(s) Includes */
#include <sxTetgen_TetraFile.h>

/* Mass-Spring Physical Representation Includes */
#include <sxVega_MassSpringSystem.h>

const static Sx::String TETGEN_NODE_EXTENSION = "node";
const static Sx::String TETGEN_ELEMENT_EXTENSION = "ele";
const static Sx::String TETGEN_FACE_EXTENSION = "face";

Sx::Vega::Storage::Vega_TetgenMassSpringMeshStorage::Vega_TetgenMassSpringMeshStorage() {
	this->density = 100.0;
	this->tensileStiffness = 8000.0;
	this->damping = 0.001;
}

Sx::Vega::Storage::Vega_TetgenMassSpringMeshStorage::~Vega_TetgenMassSpringMeshStorage() {}

std::shared_ptr<Sx::Simulation::Objects::MassSpringMesh> Sx::Vega::Storage::Vega_TetgenMassSpringMeshStorage::load(const std::shared_ptr<RendererImplementation>& renderer, const String& filename) const {
	if ( filename.length() == 0 ) {
		std::cerr << "[Vega_TetgenMassSpringMeshStorage:load] Error: Cannot create Tetrahedra mass spring mesh from filename with length 0." << std::endl;
		std::cerr << "  Tetrahedra Mass Spring Mesh not loaded, returning nullptr." << std::endl;
		return nullptr;
	}

	if ( renderer == nullptr ) {
		std::cerr << "[Vega_TetgenMassSpringMeshStorage:load] Error: Renderer cannot be a nullptr." << std::endl;
		std::cerr << "  Tetrahedra Mass Spring Mesh not loaded, returning nullptr." << std::endl;
		return nullptr;
	}

	//--------------------------------------------------------------------------
	// Construct the abstract and physical representations for the new mesh.
	//--------------------------------------------------------------------------
	std::shared_ptr<Graphics::Objects::TetrahedralMesh> mesh = std::make_shared<Graphics::Objects::TetrahedralMesh>();
	std::shared_ptr<Physics::VegaMassSpringSystem> vegaMassSpringSystem = std::make_shared<Physics::VegaMassSpringSystem>();

	String nodeFile = filename;
	nodeFile.append(".");
	nodeFile.append(TETGEN_NODE_EXTENSION);

	String eleFile = filename;
	eleFile.append(".");
	eleFile.append(TETGEN_ELEMENT_EXTENSION);

	String faceFile = filename;
	faceFile.append(".");
	faceFile.append(TETGEN_FACE_EXTENSION);

	Tetgen::File::Tetgen_TetraFile tetFile;
	
	if ( !tetFile.load(nodeFile, eleFile, faceFile) ) return false;

	//--------------------------------------------------------------------------
	// Mesh Faces
	//--------------------------------------------------------------------------
	
	for ( unsigned int i = 0; i < tetFile.getFaces().size(); i++ ) {
		Graphics::Primitives::IndiceFace curFace;

		for ( unsigned int x = 0; x < tetFile.getFaces()[i].indices.size(); x++ )
			curFace.indices.add(tetFile.getFaces()[i].indices[x]);
		mesh->addFace(curFace);
	}

	//--------------------------------------------------------------------------
	// Copy the element data from the Tet file to the TetrahedralMesh data.
	//--------------------------------------------------------------------------
	for ( unsigned int i = 0; i < tetFile.getElements().size(); i++ ) {
		Graphics::Primitives::IndiceElement curElement;

		for ( unsigned int x = 0; x < tetFile.getElements()[i].indices.size(); x++ )			
			curElement.add(tetFile.getElements()[i].indices[x]);
		mesh->addElement(curElement);
	}

	//--------------------------------------------------------------------------
	// Physical representation based off of the tetrahedral node data.
	//--------------------------------------------------------------------------
	Eigen::Vector3d curVertex;
	for ( unsigned int i = 0; i < tetFile.getNodes().size(); i++ ) {
		curVertex = tetFile.getNodes()[i].data;
		vegaMassSpringSystem->addVertex(curVertex);
	}

	mesh->setName(filename);

	//--------------------------------------------------------------------------
	// Initialize the internals of the Vega mass spring system.
	//--------------------------------------------------------------------------
	vegaMassSpringSystem->constructFromTetrahedralMesh(mesh, this->density, this->tensileStiffness, this->damping);
	
	//--------------------------------------------------------------------------
	// Construct the simulation mesh. This is an object composed of a Mesh,
	// a default renderer, and a mass-spring system.
	//--------------------------------------------------------------------------
	std::shared_ptr<MassSpringMesh> massSpringMesh = std::make_shared<MassSpringMesh>();
	massSpringMesh->setArchetype(mesh, renderer, vegaMassSpringSystem);
	massSpringMesh->construct();
	return massSpringMesh;
}

bool Sx::Vega::Storage::Vega_TetgenMassSpringMeshStorage::save(const String& filename, const std::shared_ptr<MassSpringMesh>& object) const {
	return true;
}
